////////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2003-2006 Adobe Macromedia Software LLC and its licensors.
//  All Rights Reserved. The following is Source Code and is subject to all
//  restrictions on such code as contained in the End User License Agreement
//  accompanying this product.
//
////////////////////////////////////////////////////////////////////////////////

package mx.charts
{

import mx.charts.chartClasses.CartesianChart;
import mx.charts.chartClasses.DataTip;
import mx.charts.chartClasses.DataTransform;
import mx.charts.chartClasses.Series;
import mx.charts.series.ColumnSeries;
import mx.charts.series.ColumnSet;
import mx.charts.styles.HaloDefaults;
import mx.core.mx_internal;
import mx.graphics.SolidColor;
import mx.graphics.Stroke;
import mx.styles.CSSStyleDeclaration;

import flash.filters.DropShadowFilter;
import mx.charts.chartClasses.IStackable;

use namespace mx_internal;

//--------------------------------------
//  Styles
//--------------------------------------

/**
 *  Specifies a ratio of wide to draw the columns relative to
 *  the category width, as a percentage in the range of 0 to 1. 
 *  A value of 1 uses the entire space, while a value of 0.6
 *  uses 60% of the column's available space.  
 *  The actual column width used is the smaller of the
 *  <code>columnWidthRatio</code> property and the
 *  <code>maxColumnWidth</code> property.
 *  Clustered columns divide this space proportionally
 *  among the columns in each cluster. 
 *  The default value is 0.65.
 */
[Style(name="columnWidthRatio", type="Number", inherit="no")]

/**
 *  Specifies how wide to draw the columns, in pixels.
 *  The actual column width used is the smaller of this property
 *  and the <code>columnWidthRatio</code> property.
 *  Clustered columns divide this space proportionally
 *  among the columns in each cluster. 
 */
[Style(name="maxColumnWidth", type="Number", format="Length", inherit="no")]

//--------------------------------------
//  Other metadata
//--------------------------------------

[DefaultBindingProperty(destination="dataProvider")]

[DefaultTriggerEvent("itemClick")]

[IconFile("ColumnChart.png")]

/**
 *  The ColumnChart control represents data as a series of vertical columns
 *  whose height is determined by values in the data.  
 *  You can use the ColumnChart to represent a variety of different charts
 *  including simple columns, clustered columns, stacked,
 *  100% stacked, and high/low. 
 *  
 *  <p>A ColumnChart control expects its <code>series</code> property
 *  to contain an array of ColumnSeries objects.</p>
 *
 *  <p>Stacked and 100% column charts override the <code>minField</code>
 *  property of their ColumnSeries objects.</p>
 *
 *  @mxml
 *  
 *  <p>The <code>&lt;mx:ColumnChart&gt;</code> tag inherits all the properties
 *  of its parent classes and adds the following properties:</p>
 *  
 *  <pre>
 *  &lt;mx:ColumnChart
 *    <strong>Properties</strong>
 *    type="<i>clustered|overlaid|stacked|100%</i>"
 * 
 *    <strong>Styles</strong>
 *    columnWidthRatio=".65"
 *    maxColumnWidth="<i>No default</i>"
 *  /&gt;
 *  </pre>
 *  
 *  @includeExample examples/Column_BarChartExample.mxml
 *  
 *  @see mx.charts.series.ColumnSeries
 */
public class ColumnChart extends CartesianChart
{
    include "../core/Version.as";

	//--------------------------------------------------------------------------
	//
	//  Class initialization
	//
	//--------------------------------------------------------------------------

	/**
	 *  @private
	 */
	private static var stylesInited:Boolean = initStyles();	
	
	/**
	 *  @private
	 */
	private static function initStyles():Boolean
	{
		HaloDefaults.init();

		var columnChartStyle:CSSStyleDeclaration =
			HaloDefaults.createSelector("ColumnChart");

		columnChartStyle.defaultFactory = function():void
		{
			this.axisColor = 0xD5DEDD;
			this.chartSeriesStyles = HaloDefaults.chartBaseChartSeriesStyles;		
			this.columnWidthRatio = 0.65;
			this.dataTipRenderer = DataTip;
			this.fontFamily = "Arial";
			this.fontSize = 10;
			this.fill = new SolidColor(0xFFFFFF, 0);
			this.calloutStroke = new Stroke(0x888888,2);			
			this.horizontalAxisStyleName = "blockCategoryAxis";
			this.secondHorizontalAxisStyleName = "blockCategoryAxis";
			this.secondVerticalAxisStyleName = "blockNumericAxis";
			this.textAlign = "left";
			this.verticalAxisStyleName = "blockNumericAxis";
		}

		return true;
	}

	//--------------------------------------------------------------------------
	//
	//  Class constants
	//
	//--------------------------------------------------------------------------

	/**
	 *  @private
	 */
	private static var INVALIDATING_STYLES:Object =
	{
		columnWidthRatio: 1,
		maxColumnWidth: 1
	}

	//--------------------------------------------------------------------------
	//
	//  Constructor
	//
	//--------------------------------------------------------------------------

	/**
	 *  Constructor.
	 */
	public function ColumnChart()
	{
		super();

		LinearAxis(horizontalAxis).autoAdjust = false;
		
		dataTipMode = "single";

		seriesFilters = [ new DropShadowFilter(2, 45, 0.2 * 0xFFFFFF)];
	}

	//--------------------------------------------------------------------------
	//
	//  Variables
	//
	//--------------------------------------------------------------------------
	
	/**
	 *  @private
	 */
	private var _perSeriescolumnWidthRatio:Number;
	
	/**
	 *  @private
	 */
	private var _perSeriesMaxColumnWidth:Number;
	
	/**
	 *  @private
	 */
	private var _leftOffset:Number;
	
	//--------------------------------------------------------------------------
	//
	//  Properties
	//
	//--------------------------------------------------------------------------
	
    //----------------------------------
	//  type
    //----------------------------------

	/**
	 *  @private
	 *  Storage for the type property.
	 */
	private var _type:String = "clustered";
	
	[Inspectable(category="General", enumeration="stacked,100%,clustered,overlaid", defaultValue="clustered")]

	/**
	 *  The type of the column chart.
	 *
	 *  <p>Possible values are:</p>
	 *  <ul>
	 *    <li><code>"clustered"</code>:
	 *    Values from different series are grouped by category.
	 *    This is the default type.</li>
	 *    <li><code>"overlaid"</code>:
	 *    Multiple values are rendered on top of one another by category,
	 *    with the last series on top. </li>
	 *    <li><code>"stacked"</code>:
	 *    Columns are stacked on top of each other and grouped by category. 
	 *    Each column represents the cumulative value
	 *    of the columns beneath it. </li>
	 *    <li><code>"100%"</code>:
	 *    Columns are stacked on top of each other, adding up to 100%. 
	 *    Each column represents the percent that it contributes
	 *    to the sum of the values for that category.</li>
	 *  </ul>
	 */
	public function get type():String
	{
		return _type;
	}

	/**
	 *  @private
	 */
	public function set type(value:String):void
	{
		if (_type == value)
			return;
			
		_type = value;

		invalidateSeries();
		invalidateData();
	}

	//--------------------------------------------------------------------------
	//
	//  Overridden methods: UIComponent
	//
	//--------------------------------------------------------------------------

	/**
	 *  @private
	 */
	override public function styleChanged(styleProp:String):void
	{
		if (styleProp == null || INVALIDATING_STYLES[styleProp] != undefined)
			invalidateSeries();

		super.styleChanged(styleProp);
	}

	//--------------------------------------------------------------------------
	//
	//  Overridden methods: ChartBase
	//
	//--------------------------------------------------------------------------

	/**
	 *  @private
	 */
	override protected function customizeSeries(seriesGlyph:Series, i:uint):void
	{
		if (seriesGlyph is ColumnSeries || seriesGlyph is ColumnSet)
		{
			var series:Object = seriesGlyph;
			
			if (!isNaN(_perSeriescolumnWidthRatio))
				series.columnWidthRatio = _perSeriescolumnWidthRatio;

			if (!isNaN(_perSeriesMaxColumnWidth))
				series.maxColumnWidth = _perSeriesMaxColumnWidth;

			if (_type == "overlaid")		
				series.offset = 0;
			else
				series.offset = _leftOffset + i * _perSeriescolumnWidthRatio;
	
			if (series is IStackable)
			{
				var stackSeries:IStackable = IStackable(series);
				stackSeries.stacker = null;
				stackSeries.stackTotals = null;
			}
		}
	}
	
	/**
	 *  @private
	 */
	override protected function applySeriesSet(seriesSet:Array,
											   transform:DataTransform):Array
	{
		var columnWidthRatio:Number = getStyle("columnWidthRatio");
		var maxColumnWidth:Number = getStyle("maxColumnWidth");

		switch (_type)
		{
			case "stacked":
			case "100%":
			{
				var n:int = seriesSet.length;
				for (var i:int = 0; i < n; i++)
				{
					seriesSet[i].offset = 0;
				}

				var newSeriesGlyph:ColumnSet = new ColumnSet();
				newSeriesGlyph.series = seriesSet;

				if (!isNaN(columnWidthRatio))
					newSeriesGlyph.columnWidthRatio = columnWidthRatio;

				if (!isNaN(maxColumnWidth))
					newSeriesGlyph.maxColumnWidth = maxColumnWidth;

				newSeriesGlyph.type = _type;

				invalidateData();
			
				return [ newSeriesGlyph ];
			}				

			case "clustered":
			default:
			{
				_perSeriescolumnWidthRatio = columnWidthRatio / seriesSet.length;
				_perSeriesMaxColumnWidth = maxColumnWidth / seriesSet.length;
				
				_leftOffset = (1 - columnWidthRatio) / 2 +
							  _perSeriescolumnWidthRatio / 2 - 0.5;

				return super.applySeriesSet(seriesSet, transform);
			}

			case "overlaid":
			{
				_perSeriescolumnWidthRatio = columnWidthRatio;
				_perSeriesMaxColumnWidth = maxColumnWidth;

				_leftOffset = 0;
				return super.applySeriesSet(seriesSet, transform);
			}
		}
	}			
	
	//--------------------------------------------------------------------------
	//
	//  Overridden methods: CartesianChart
	//
	//--------------------------------------------------------------------------

	/**
	 *  @private
	 */
	override protected function initSecondaryMode():void
	{
		super.initSecondaryMode();

		if (!secondVerticalAxis)
			secondVerticalAxis = new LinearAxis();

		if (!secondVerticalAxisRenderer)
			secondVerticalAxisRenderer = new AxisRenderer();			
	}
}

}
